/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.utils;

import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.web.ext.Assignable;
import cn.easyplatform.web.ext.zul.Actionbox;
import cn.easyplatform.web.ext.zul.BandboxExt;
import cn.easyplatform.web.ext.zul.Checkgroup;
import cn.easyplatform.web.task.EventSupport;
import cn.easyplatform.web.task.event.EventListenerHandler;
import cn.easyplatform.web.task.zkex.simple.ActionboxBuilder;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.zkoss.image.AImage;
import org.zkoss.sound.AAudio;
import org.zkoss.util.media.AMedia;
import org.zkoss.util.resource.Labels;
import org.zkoss.video.AVideo;
import org.zkoss.zk.ui.*;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.ext.Disable;
import org.zkoss.zk.ui.metainfo.EventHandler;
import org.zkoss.zk.ui.metainfo.EventHandlerMap;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zkex.zul.Colorbox;
import org.zkoss.zkex.zul.Fisheye;
import org.zkoss.zkex.zul.Pdfviewer;
import org.zkoss.zkmax.zul.*;
import org.zkoss.zul.Calendar;
import org.zkoss.zul.Timer;
import org.zkoss.zul.*;
import org.zkoss.zul.impl.FormatInputElement;
import org.zkoss.zul.impl.InputElement;
import org.zkoss.zul.impl.LabelImageElement;
import org.zkoss.zul.impl.XulElement;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public final class PageUtils {

    public final static Object getValue(Component comp, boolean isCheck) {
        if (comp instanceof InputElement) {
            InputElement input = (InputElement) comp;
            if (isCheck && input.getConstraint() != null) {
                if (Components.isRealVisible(input)) {
                    Component c = input.getParent();
                    boolean noCheck = false;
                    while (!(c instanceof IdSpace)) {
                        if (!c.isVisible()) {
                            noCheck = true;
                            break;
                        }
                        c = c.getParent();
                    }
                    if (!noCheck)
                        input.getConstraint().validate(comp, input.getText());
                } else
                    input.setConstraint((String) null);
            }
            if (input.getRawValue() != null && comp instanceof Datebox && "long".equals(comp.getAttribute("type")))
                return ((Date) input.getRawValue()).getTime();
            if (input instanceof Actionbox)
                return ((Actionbox) input).getRealValue();
            else if (input instanceof BandboxExt)
                return ((BandboxExt) input).getValue();
            return input.getRawValue();
        }

        if (comp instanceof Assignable)
            return ((Assignable) comp).getValue();

        if (comp instanceof Checkbox) {
            if (comp instanceof Radio) {
                Radio r = (Radio) comp;
                return r.getValue();
            } else
                return ((Checkbox) comp).isChecked();
        }

        if (comp instanceof Tbeditor)
            return ((Tbeditor) comp).getValue();

        if (comp instanceof Colorbox)
            return ((Colorbox) comp).getValue();

        if (comp instanceof Slider)
            return ((Slider) comp).getCurposInDouble();

        if (comp instanceof Calendar)
            return ((Calendar) comp).getValue();

        if (comp instanceof Rating)
            return ((Rating) comp).getRating();

        if (comp instanceof Barcode)
            return ((Barcode) comp).getValue();

        /**
         if (comp instanceof LabelImageElement) {
         LabelImageElement label = (LabelImageElement) comp;
         return label.getLabel();
         }
         if (comp instanceof Image)
         return ((Image) comp).getSrc();*/
        //所有其它组件取attribute值
        return comp.getAttribute("value");
    }

    public final static void setValue(Component comp, Object value) {
        setValue(comp, value, null);
    }

    public final static void setValue(Component comp, Object value,
                                      String format) {
        if (comp instanceof Assignable) {
            ((Assignable) comp).setValue(value);
        } else if (comp instanceof InputElement) {
            if (value != null) {
                if (comp instanceof FormatInputElement) {
                    FormatInputElement input = (FormatInputElement) comp;
                    if (value instanceof Number) {
                        if (comp instanceof Doublebox
                                || comp instanceof Decimalbox
                                || comp instanceof Doublespinner)
                            value = ((Number) value).doubleValue();
                        else if (comp instanceof Intbox
                                || comp instanceof Spinner)
                            value = ((Number) value).intValue();
                        else if (comp instanceof Longbox)
                            value = ((Number) value).longValue();
                        else if (comp instanceof Datebox) {//时间
                            value = new Date(((Number) value).longValue());
                            comp.setAttribute("type", "long");
                        }
                        input.setRawValue(value);
                    } else {
                        if (value instanceof String)
                            input.setText((String) value);
                        else
                            input.setRawValue(value);
                    }
                } else if (comp instanceof Actionbox) {
                    Actionbox ab = (Actionbox) comp;
                    ab.setRealValue(value);
                    if (ab.isCombo() && !Strings.isBlank(ab.getComboQuery())) {
                        ActionboxBuilder abb = (ActionboxBuilder) ab
                                .getEventListeners(Events.ON_OPEN).iterator()
                                .next();
                        abb.setLabel(ab.getRealValue());
                    }
                } else if (comp instanceof Textbox) {
                    if (!(value instanceof String || value instanceof Character)) {
                        Clients.wrongValue(comp,
                                Labels.getLabel("component.value.match"));
                        ((InputElement) comp).setRawValue(value.toString());
                    } else
                        ((InputElement) comp).setRawValue(value.toString());
                } else
                    ((InputElement) comp).setRawValue(value);
            } else if (comp instanceof Actionbox) {
                ((Actionbox) comp).setRealValue(value);
            } else
                ((InputElement) comp).setRawValue(value);
        } else if (comp instanceof Checkbox) {
            Checkbox cbx = (Checkbox) comp;
            if (value != null) {
                if (value instanceof Number) {
                    Number num = (Number) value;
                    cbx.setChecked(num.intValue() > 0);
                } else if (value instanceof Boolean)
                    cbx.setChecked((Boolean) value);
                else {
                    String str = value.toString();
                    if (str.length() == 1)
                        cbx.setChecked("1".equals(str) || "T".equals(str) || "Y".equals(str));
                    else
                        cbx.setChecked(value.toString()
                                .equalsIgnoreCase("true"));
                }
                // cbx.setValue(value);
            } else
                cbx.setChecked(false);
        } else if (comp instanceof Colorbox) {
            Colorbox cb = (Colorbox) comp;
            cb.setValue(Strings.isBlank((String) value) ? null : value
                    .toString());
        } else if (comp instanceof Tbeditor) {
            ((Tbeditor) comp).setValue(value == null ? null : value.toString());
        } else if (comp instanceof Rating) {
            Rating rating = (Rating) comp;
            if (value != null) {
                if (value instanceof Number) {
                    Number num = (Number) value;
                    rating.setRating(num.intValue());
                } else if (value instanceof String) {
                    rating.setRating(Nums.toInt(value, 0));
                } else
                    rating.setRating(0);
            } else rating.setRating(0);
        } else if (comp instanceof Cropper) {
            Cropper cropper = (Cropper) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (value instanceof byte[]) {
                    try {
                        org.zkoss.image.Image img = new AImage("",
                                (byte[]) value);
                        cropper.setContent(img);
                    } catch (IOException ex) {
                    }
                } else if (value instanceof String) {
                    String src = (String) value;
                    if (src.startsWith("$7")) {
                        try {
                            cropper.setSrc("/servlets/download?id="
                                    + URLEncoder.encode(src, "utf8"));
                        } catch (UnsupportedEncodingException e) {
                        }
                    } else if (!src.trim().equals("")) {
                        if (src.length() > 200) {
                            try {
                                org.zkoss.image.Image img = new AImage("",
                                        (Base64.decodeBase64(src)));
                                cropper.setContent(img);
                            } catch (Exception ex) {
                                cropper.setSrc(src);
                            }
                        } else {
                            cropper.setSrc(src);
                        }
                    } else
                        cropper.setSrc(null);
                } else
                    cropper.setSrc(null);
            } else
                cropper.setSrc(null);
        } else if (comp instanceof Barcode) {
            Barcode bc = (Barcode) comp;
            if (value != null)
                bc.setValue(value.toString());
            else
                bc.setValue("");
        } else if (comp instanceof Label) {
            Label label = (Label) comp;
            comp.setAttribute("value", value);
            if (Strings.isBlank(label.getValue()))
                label.setValue(value == null ? "" : value.toString());
            else if (value != null) {
                if (label.getValue().contains("###")) {
                    label.setAttribute("format", label.getValue());
                    label.setValue(WebUtils.format(label.getValue(), value));
                } else {
                    format = (String) label.getAttribute("format");
                    if (format != null)
                        label.setValue(WebUtils.format(format, value));
                    else
                        label.setValue(value.toString());
                }
            } else
                label.setValue("");
        } else if (comp instanceof Image) {
            Image image = (Image) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (value instanceof byte[]) {
                    try {
                        org.zkoss.image.Image img = new AImage("",
                                (byte[]) value);
                        image.setContent(img);
                    } catch (IOException ex) {
                    }
                } else if (value instanceof String) {
                    String src = (String) value;
                    if (src.startsWith("$7")) {
                        try {
                            image.setSrc("/servlets/download?id="
                                    + URLEncoder.encode(src, "utf8"));
                        } catch (UnsupportedEncodingException e) {
                        }
                    } else if (!src.trim().equals("")) {
                        if (src.length() > 200) {
                            try {
                                org.zkoss.image.Image img = new AImage("",
                                        (Base64.decodeBase64(src)));
                                image.setContent(img);
                            } catch (Exception ex) {
                                image.setSrc(src);
                            }
                        } else {
                            image.setSrc(src);
                        }
                    } else
                        image.setSrc(null);
                } else
                    image.setSrc(null);
            } else
                image.setSrc(null);
        } else if (comp instanceof LabelImageElement) {
            LabelImageElement label = (LabelImageElement) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (comp instanceof Fisheye) {
                    Fisheye eye = (Fisheye) comp;
                    if (value instanceof byte[]) {
                        try {
                            org.zkoss.image.Image img = new AImage("",
                                    (byte[]) value);
                            eye.setImageContent(img);
                        } catch (IOException ex) {
                        }
                    } else if (value instanceof String) {
                        String src = (String) value;
                        if (src.startsWith("$7")) {
                            try {
                                eye.setImage("/servlets/download?id="
                                        + URLEncoder.encode(src, "utf8"));
                            } catch (UnsupportedEncodingException e) {
                            }
                        } else if (!src.trim().equals("")) {
                            if (src.length() > 200) {
                                try {
                                    org.zkoss.image.Image img = new AImage("",
                                            (Base64.decodeBase64(src)));
                                    eye.setImageContent(img);
                                } catch (IOException ex) {
                                }
                            } else {
                                eye.setImage(src);
                            }
                        } else
                            eye.setImage(null);
                    }
                } else if (!Strings.isBlank(format))
                    label.setLabel(WebUtils.format(format, value));
                else {
                    if (comp instanceof Button) {
                        if (Strings.isBlank(((Button) comp).getLabel()))
                            label.setLabel(value.toString());
                    } else
                        label.setLabel(value.toString());
                }
            } else
                label.setLabel("");
        } else if (comp instanceof Slider) {
            Slider slider = (Slider) comp;
            if (value != null) {
                if (!(value instanceof Number)) {
                    Clients.wrongValue(comp,
                            Labels.getLabel("component.value.match"));
                } else
                    slider.setCurpos(((Number) value).doubleValue());
            } else
                slider.setCurpos(0d);
        } else if (comp instanceof Calendar) {
            Calendar calendar = (Calendar) comp;
            calendar.setValue((Date) value);
        } else if (comp instanceof Video) {
            Video video = (Video) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (value instanceof byte[]) {
                    try {
                        AVideo c = new AVideo("",
                                (byte[]) value);
                        video.setContent(c);
                    } catch (IOException ex) {
                    }
                } else if (value instanceof String) {
                    String src = (String) value;
                    if (src.startsWith("$7")) {
                        try {
                            video.setSrc("/servlets/download?id="
                                    + URLEncoder.encode(src, "utf8"));
                        } catch (UnsupportedEncodingException e) {
                        }
                    } else if (!src.trim().equals("")) {
                        if (src.length() > 200) {
                            try {
                                AVideo c = new AVideo("",
                                        (Base64.decodeBase64(src)));
                                video.setContent(c);
                            } catch (IOException ex) {
                            }
                        } else {
                            video.setSrc(src);
                        }
                    } else
                        video.setSrc(null);
                } else
                    video.setSrc(null);
            } else
                video.setSrc(null);
        } else if (comp instanceof Audio) {
            Audio audio = (Audio) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (value instanceof byte[]) {
                    try {
                        AAudio c = new AAudio("",
                                (byte[]) value);
                        audio.setContent(c);
                    } catch (IOException ex) {
                    }
                } else if (value instanceof String) {
                    String src = (String) value;
                    if (src.startsWith("$7")) {
                        try {
                            audio.setSrc("/servlets/download?id="
                                    + URLEncoder.encode(src, "utf8"));
                        } catch (UnsupportedEncodingException e) {
                        }
                    } else if (!src.trim().equals("")) {
                        if (src.length() > 200) {
                            try {
                                AAudio c = new AAudio("",
                                        (Base64.decodeBase64(src)));
                                audio.setContent(c);
                            } catch (IOException ex) {
                            }
                        } else {
                            audio.setSrc(src);
                        }
                    } else
                        audio.setSrc((String) null);
                } else
                    audio.setSrc((String) null);
            } else
                audio.setSrc((String) null);
        } else if (comp instanceof Html) {
            Html label = (Html) comp;
            comp.setAttribute("value", value);
            label.setContent((String) value);
        } else if (comp instanceof Pdfviewer) {
            Pdfviewer pdfviewer = (Pdfviewer) comp;
            comp.setAttribute("value", value);
            if (value != null) {
                if (value instanceof byte[]) {
                    pdfviewer.setContent(new AMedia("output", "pdf", "application/pdf", (byte[]) value));
                } else if (value instanceof String) {
                    String src = (String) value;
                    if (src.startsWith("$7")) {
                        try {
                            pdfviewer.setSrc("/servlets/download?id="
                                    + URLEncoder.encode(src, "utf8"));
                        } catch (UnsupportedEncodingException e) {
                        }
                    } else if (!src.trim().equals("")) {
                        if (src.length() > 200) {
                            pdfviewer.setContent(new AMedia("", "pdf", "application/pdf", Base64.decodeBase64(src)));
                        } else {
                            pdfviewer.setSrc(src);
                        }
                    } else
                        pdfviewer.setSrc((String) null);
                } else
                    pdfviewer.setSrc((String) null);
            } else
                pdfviewer.setSrc((String) null);
        }
    }

    public final static void save(Collection<Component> managedInputComponents) {
        for (Component comp : managedInputComponents) {
            if (comp instanceof InputElement) {
                InputElement input = (InputElement) comp;
                input.setAttribute("readonly", input.isReadonly());
                input.setAttribute("disabled", input.isDisabled());
            } else if (comp instanceof Checkbox) {
                Checkbox cbx = (Checkbox) comp;
                cbx.setAttribute("disabled", cbx.isDisabled());
            } else if (comp instanceof Disable) {
                Disable dis = (Disable) comp;
                comp.setAttribute("disabled", dis.isDisabled());
            } else if (comp instanceof Colorbox) {
                Colorbox cb = (Colorbox) comp;
                comp.setAttribute("disabled", cb.isDisabled());
            }
        }
    }

    public final static void disabled(Collection<Component> managedInputComponents) {
        for (Component comp : managedInputComponents)
            disabled(comp);
    }

    public final static void disabled(Component comp) {
        if (comp instanceof InputElement) {
            InputElement input = (InputElement) comp;
            input.setDisabled(true);
        } else if (comp instanceof Checkbox) {
            Checkbox cbx = (Checkbox) comp;
            cbx.setDisabled(true);
        } else if (comp instanceof Disable) {
            ((Disable) comp).setDisabled(true);
        } else if (comp instanceof Colorbox)
            ((Colorbox) comp).setDisabled(true);
    }

    /**
     * 检查页面组件的权限
     *
     * @param list
     * @param comp
     */
    public final static void checkAccess(String[] list, Component comp) {
        if (!Strings.isBlank(comp.getAccess()) && list != null) {
            if (!ArrayUtils.contains(list, comp.getAccess())) {
                if (comp.getAccess().endsWith("_V")) {
                    comp.setVisible(false);
                } else {
                    PageUtils.disabled(comp);
                }
            }
        }
    }

    public final static void reset(Collection<Component> managedInputComponents) {
        for (Component comp : managedInputComponents) {
            if (comp instanceof InputElement) {
                InputElement input = (InputElement) comp;
                input.setDisabled((Boolean) input.getAttribute("disabled"));
                input.setReadonly((Boolean) input.getAttribute("readonly"));
            } else if (comp instanceof Checkbox) {
                Checkbox cbx = (Checkbox) comp;
                cbx.setDisabled((Boolean) cbx.getAttribute("disabled"));
            } else if (comp instanceof Disable) {
                ((Disable) comp).setDisabled((Boolean) comp
                        .getAttribute("disabled"));
            } else if (comp instanceof Colorbox) {
                ((Colorbox) comp).setDisabled((Boolean) comp
                        .getAttribute("disabled"));
            }
        }
    }

    public final static String getComponentDefaultEventName(Component target) {
        String eventName = null;
        if (target instanceof InputElement || target instanceof Colorbox || target instanceof Tbeditor || target instanceof Rating || target instanceof Stepbar)
            eventName = Events.ON_CHANGE;
        else if (target instanceof Button) {
            Button button = (Button) target;
            if (Strings.isBlank(button.getUpload()))
                eventName = Events.ON_CLICK;
            else
                eventName = Events.ON_UPLOAD;
        } else if (target instanceof Checkbox || target instanceof Radiogroup
                || target instanceof Checkgroup)
            eventName = Events.ON_CHECK;
        else if (target instanceof Chosenbox || target instanceof Selectbox
                || target instanceof Listbox || target instanceof Tree)
            eventName = Events.ON_SELECT;
        else if (target instanceof Timer)
            eventName = Events.ON_TIMER;
        else if (target instanceof Organigram)
            eventName = Events.ON_SELECT;
        else if (target instanceof Orgitem)
            eventName = Events.ON_OPEN;
        else if (target instanceof Slider)
            eventName = Events.ON_SCROLL;
        else if (target instanceof Camera)
            eventName = "onSnapshotUpload";
        else if (target instanceof Signature)
            eventName = "onSave";
        else if (target instanceof Cropper)
            eventName = "onCrop";
        else if (target instanceof Barcodescanner)
            eventName = "onDetect";
        else
            eventName = Events.ON_CLICK;
        return eventName;
    }

    public final static void addEventListener(EventSupport taskHandler,
                                              String eventName, Component comp) {
        if (Strings.isBlank(eventName))
            throw new IllegalArgumentException("event name is not empty");
        comp.addEventListener(eventName, new EventListenerHandler(eventName,
                taskHandler, comp.getEvent(), null));
    }

    public final static void processEventHandler(EventSupport taskHandler, Component comp, Component anchor) {
        //处理默认事件
        if (!Strings.isBlank(comp.getEvent())) {
            String eventName = null;
            if (Events.isValid(comp.getEvent())) {// 处理onClick:事件内容,灵活定义事件类型
                char[] cs = comp.getEvent().toCharArray();
                int i = 0;
                boolean isSep = false;
                StringBuilder sb = new StringBuilder();
                while (true) {
                    if (cs[i] == ':') {
                        isSep = true;
                        break;
                    }
                    if (Character.isLetter(cs[i]))
                        sb.append(cs[i]);
                    else
                        break;
                    i++;
                }
                if (isSep && sb.length() > 0) {
                    eventName = sb.toString();
                    ((AbstractComponent) comp).setEvent(comp.getEvent()
                            .substring(i + 1).trim());
                    sb = null;
                }
            }
            if (eventName == null)
                eventName = getComponentDefaultEventName(comp);
            comp.addEventListener(eventName, new EventListenerHandler(eventName,
                    taskHandler, comp.getEvent(), anchor));
        }
        //处理其它明确的事件对象
        EventHandlerMap em = comp.getEventHandlerMap();
        if (em != null && !em.isEmpty()) {
            em.getEventNames().forEach(name -> {
                List<EventHandler> evts = em.getAll(name);
                evts.forEach(eh -> {
                    if (eh.isEffective(comp)) {
                        comp.addEventListener(name, new EventListenerHandler(name,
                                taskHandler, eh.getZScript().getRawContent(), anchor));
                    }
                });
            });
        }
    }

    public final static XulElement createInputComponent(FieldType type) {
        switch (type) {
            case CHAR:
            case VARCHAR:
            case CLOB:
                return new Textbox();
            case BOOLEAN:
                return new Checkbox();
            case DATETIME:
            case DATE:
                return new Datebox();
            case TIME:
                return new Timebox();
            case INT:
                return new Intbox();
            case LONG:
                return new Longbox();
            case NUMERIC:
                return new Doublebox();
            default:
                return null;
        }
    }

    public final static String getComponentLabel(Component comp) {
        if (comp instanceof Checkbox)
            return String.valueOf(((Checkbox) comp).isChecked());
        if (comp instanceof LabelImageElement)
            return ((LabelImageElement) comp).getLabel();
        if (comp instanceof Combobox)
            return ((Combobox) comp).getText();
        if (comp instanceof Label)
            return ((Label) comp).getValue();
        Object o = getValue(comp, false);
        return o == null ? "" : o.toString();
    }

    public final static void setTaskIcon(LabelImageElement c, String icon) {
        if (!Strings.isBlank(icon)) {
            if (icon.startsWith("z-icon-") || icon.indexOf(' ') > 0) {
                if (c instanceof Menuitem)
                    c.setIconSclass(icon + " z-menu-image");
                else
                    c.setIconSclass(icon);
            } else
                c.setImage("/images/task/" + icon);
        } else if (c instanceof Menuitem) {
            c.setIconSclass("z-icon-list-alt z-menu-image");
        } else if (c instanceof Tab || c instanceof Treecell) {
            c.setIconSclass("z-icon-list-alt");
        } else
            c.setIconSclass("z-icon-user");
    }

    public final static int[] getActionboxIndexes(String mapping,
                                                  List<ListHeaderVo> headers) {
        String[] names = mapping.split(",");
        int[] indexes = new int[names.length];
        for (int i = 0; i < indexes.length; i++) {
            int index = 0;
            for (ListHeaderVo header : headers) {
                if (names[i].trim().equals(header.getName())) {
                    indexes[i] = index;
                    break;
                }
                index++;
            }
        }
        return indexes;
    }

    /**
     * 绑定页面变量
     *
     * @param name
     * @param value
     * @param target
     */
    public final static void bindVariable(String name, Object value, Component target) {
        if (value == null)
            target.setAttribute(name, value);
        else {
            if (value instanceof List<?>) {
                List<?> data = (List<?>) value;
                if (!data.isEmpty() && data.get(0) instanceof String) {
                    String c = (String) data.get(0);
                    if (c.startsWith("{") && c.endsWith("}")) {
                        List<Object> newc = new ArrayList<>(data.size());
                        try {
                            for (Object obj : data) {
                                newc.add(mapper.readValue((String) obj, Map.class));
                            }
                        } catch (IOException e) {
                        }
                        target.setAttribute(name, new ListModelList<>(newc));
                        return;
                    }
                }
                target.setAttribute(name, new ListModelList<>((List<?>) value));
            } else if (value.getClass().isArray()) {
                Object[] data = (Object[]) value;
                if (data.length > 0 && data[0] instanceof String) {
                    String c = (String) data[0];
                    if (c.startsWith("{") && c.endsWith("}")) {
                        List<Object> newc = new ArrayList<>(data.length);
                        try {
                            for (Object obj : data) {
                                newc.add(mapper.readValue((String) obj, Map.class));
                            }
                        } catch (IOException e) {
                        }
                        target.setAttribute(name, new ListModelArray<>(newc));
                        return;
                    }
                }
                target.setAttribute(name, new ListModelArray<>((Object[]) value));
            } else if (value instanceof Map)
                target.setAttribute(name, new ListModelMap<>((Map) value));
            else if (value instanceof Set)
                target.setAttribute(name, new ListModelSet<>((Set) value));
            else
                target.setAttribute(name, value);
        }
    }

    private final static ObjectMapper mapper = new ObjectMapper();
}
